<template>
  <div class="s-form-view-container">
    <el-form
      :model="addForm"
      :inline="isInline"
      :label-position="position"
      :label-width="labelWidth"
      :size="formSize"
      status-icon
      ref="addFormRef"
    >
      <el-form-item
        v-for="(item, i) in showList"
        :key="i"
        :label="item.header + '：'"
        :rules="Object.keys(rules).length > 0 ? rules : item.rule"
        :prop="item.field"
      >
        <template>
          <!-- text、email、textarea类型 -->
          <el-input
            v-if="
              (!item.hidden && item.type === 'text') || item.type === 'textarea'
            "
            :type="item.type"
            :placeholder="item.placeholder"
            :disabled="item.disabled"
            v-model="addForm[item.field]"
            clearable
            :style="{ width: valueWidth }"
          />
          <!-- 密码 -->
          <el-input
            v-else-if="!item.hidden && item.type === 'password'"
            type="password"
            :placeholder="item.placeholder"
            :disabled="item.disabled"
            v-model="addForm[item.field]"
            clearable
            :style="{ width: valueWidth }"
            show-password
          />
          <!-- 带输入建议的输入框 -->
          <el-autocomplete
            v-else-if="!item.hidden && item.type === 'autocomplete'"
            v-model="addForm[item.field]"
            :fetch-suggestions="
              (queryString, cb) => {
                autocompleteQuerySearch(queryString, cb, item);
              }
            "
            :placeholder="item.placeholder"
            @select="autocompleteHandleSelect($event, item)"
            :disabled="item.disabled"
            clearable
            :style="{ width: valueWidth }"
            :trigger-on-focus="!item.autocomplete"
          />
          <!-- number类型 -->
          <el-input-number
            v-else-if="!item.hidden && item.type === 'number'"
            v-model="addForm[item.field]"
            controls-position="right"
            @change="changeNumber"
            :disabled="item.disabled"
            :placeholder="item.placeholder"
            clearable
            :min="item.min"
            :max="item.max"
            :style="{ width: valueWidth }"
          />
          <!-- number类型2 -->
          <el-input
            v-if="!item.hidden && item.type === 'number2'"
            :type="item.type"
            :placeholder="item.placeholder"
            :disabled="item.disabled"
            v-model.number="addForm[item.field]"
            clearable
            :style="{ width: valueWidth }"
          />
          <!-- 日期类型 -->
          <el-date-picker
            v-else-if="!item.hidden && item.type === 'date'"
            type="date"
            v-model="addForm[item.field]"
            align="left"
            clearable
            format="yyyy-MM-dd"
            value-format="yyyy-MM-dd"
            placeholder="请选择日期"
            :style="{ width: valueWidth }"
            :disabled="item.disabled"
            @change="changeDate"
          />
          <!-- 时间 -->
          <el-date-picker
            v-else-if="!item.hidden && item.type === 'datetime'"
            type="datetime"
            v-model="addForm[item.field]"
            align="left"
            clearable
            format="yyyy-MM-dd HH:mm:ss"
            value-format="yyyy-MM-dd HH:mm:ss"
            placeholder="请选择时间"
            :style="{ width: valueWidth }"
            :disabled="item.disabled"
            @change="changeDate"
          />
          <!-- 年 -->
          <el-date-picker
            v-else-if="!item.hidden && item.type === 'year'"
            type="year"
            v-model="addForm[item.field]"
            align="left"
            clearable
            format="yyyy 年"
            value-format="yyyy"
            placeholder="请选择年份"
            :style="{ width: valueWidth }"
            :disabled="item.disabled"
            @change="changeYear"
          />
          <!-- 月 -->
          <el-date-picker
            v-else-if="!item.hidden && item.type === 'month'"
            type="month"
            v-model="addForm[item.field]"
            align="left"
            clearable
            format="MM 月"
            value-format="MM"
            placeholder="请选择月份"
            :style="{ width: valueWidth }"
            :disabled="item.disabled"
            @change="changeMonth"
          />
          <!-- 时间日期范围 -->
          <el-date-picker
            v-else-if="!item.hidden && item.type === 'datetimerange'"
            type="datetimerange"
            v-model="addForm[item.field]"
            align="left"
            clearable
            range-separator="至"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
            :style="{ width: item.width }"
            :disabled="item.disabled"
            @change="changeDateTimeRange"
          />
          <!-- 日期范围 -->
          <el-date-picker
            v-else-if="!item.hidden && item.type === 'daterange'"
            type="daterange"
            v-model="addForm[item.field]"
            align="left"
            clearable
            format="yyyy-MM-dd"
            value-format="yyyy-MM-dd"
            range-separator="至"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
            :style="{ width: item.width }"
            :disabled="item.disabled"
            @change="changeDateRange"
          />
          <!-- 下拉框 -->
          <el-select
            v-else-if="!item.hidden && item.type === 'select'"
            v-model="addForm[item.field]"
            clearable
            :filterable="filterable"
            placeholder="请选择"
            :style="{ width: valueWidth }"
            :disabled="item.disabled"
            @change="changeOption($event, item)"
            value-key="id"
          >
            <el-option
              v-for="op in item.option"
              :key="op.value"
              :label="op.label"
              :value="op.value"
              :disabled="op.disabled"
            />
          </el-select>
          <!-- 可编辑的下拉菜单 -->
          <el-select
            v-else-if="!item.hidden && item.type === 'selectCanedit'"
            v-model="addForm[item.field]"
            filterable
            allow-create
            placeholder="请选择"
            clearable
            :style="{ width: valueWidth }"
            @change="editSelectChange"
          >
            <el-option
              v-for="op in item.option"
              :key="op.value"
              :label="op.label"
              :value="op.value"
            />
          </el-select>
          <!-- 多选下拉框 -->
          <el-select
            v-else-if="!item.hidden && item.type === 'multiSelect'"
            v-model="addForm[item.field]"
            multiple
            clearable
            :filterable="filterable"
            :collapse-tags="collapseTags"
            placeholder="请选择"
            :style="{ width: valueWidth }"
            :disabled="item.disabled"
            @change="changeMultOption($event, item)"
          >
            <el-option
              v-for="op in item.option"
              :key="op.value"
              :label="op.label"
              :value="op.value"
              :disabled="op.disabled"
            />
          </el-select>
          <!-- 级联下拉框 -->
          <el-cascader
            v-else-if="!item.hidden && item.type === 'selectCascader'"
            v-model="addForm[item.field]"
            :options="item.option"
            :props="item.props"
            placeholder="请选择"
            clearable
            :filterable="filterable"
            :style="{ width: valueWidth }"
            @change="cascaderSelectChange"
            @expand-change="cascaderItemChange"
          />
          <!-- 单选框 -->
          <el-radio-group
            v-else-if="!item.hidden && item.type === 'radio'"
            v-model="addForm[item.field]"
            :style="{ width: valueWidth }"
            @change="changeRadio"
          >
            <el-radio
              v-for="ra in item.option"
              :key="ra.value"
              :label="ra.value"
              :disabled="ra.disabled"
              >{{ ra.label }}
            </el-radio>
          </el-radio-group>
          <!-- 多选框 -->
          <el-checkbox-group
            v-else-if="!item.hidden && item.type === 'checkbox'"
            v-model="addForm[item.field]"
            @change="checkedChange"
          >
            <el-checkbox
              v-for="(op, i) in item.option"
              :key="i"
              :label="op.value"
              :disabled="op.disabled"
              >{{ op.label }}
            </el-checkbox>
          </el-checkbox-group>
          <!-- 取色器 -->
          <el-color-picker
            v-else-if="!item.hidden && item.type === 'colorPicker'"
            v-model="addForm[item.field]"
            :show-alpha="showAlpha"
            :predefine="predefineColors"
            @change="colorPickerChange"
            @active-change="colorPickerActiveChange"
          />
          <!-- 文件或图片上传 -->
          <div v-else-if="!item.hidden && item.type === 'upload'">
            <el-upload
              :action="uploadAttr.action"
              :headers="uploadAttr.headers"
              :multiple="uploadAttr.multiple"
              :data="uploadAttr.data"
              :name="uploadAttr.name"
              :with-credentials="uploadAttr.withCredentials"
              :show-file-list="uploadAttr.showFileList"
              :drag="uploadAttr.drag"
              :accept="uploadAttr.accept"
              :list-type="uploadAttr.listType"
              :auto-upload="uploadAttr.autoUpload"
              :file-list="addForm[item.field]"
              :disabled="uploadAttr.disabled"
              :limit="uploadAttr.limit"
              :on-preview="onPreview"
              :on-remove="onRemove"
              :on-success="onSuccess"
              :on-error="onError"
              :on-progress="onProgress"
              :on-change="onChange"
              :before-upload="beforeUpload"
              :before-remove="beforeRemove"
              ref="upload"
            >
              <!--  按钮 -->
              <el-button
                :size="formSize"
                type="primary"
                v-if="
                  uploadAttr.listType !== 'picture-card' &&
                  uploadAttr.drag === false
                "
              >
                {{ uploadAttr.btnTitle }}
              </el-button>
              <!-- 拖放上传 -->
              <div v-else-if="uploadAttr.drag">
                <i class="el-icon-upload" />
                <div class="el-upload__text">
                  将文件拖到此处，或<em>点击上传</em>
                </div>
              </div>
              <!-- 照片墙 -->
              <i class="el-icon-plus" v-else />
              <!-- 提示说明文字 -->
              <div slot="tip" class="el-upload__tip">
                {{ uploadAttr.slotContent }}
              </div>
            </el-upload>
            <!--  图片弹出框 -->
            <el-dialog :visible.sync="dialogVisible">
              <img width="100%" :src="dialogImageUrl" alt="" />
            </el-dialog>
          </div>
          <div v-else-if="!item.hidden && item.type === 'custom'">
            <slot name="custom" :item="item"></slot>
          </div>
          <!--  富文本编辑器 -->
          <div v-else-if="!item.hidden && item.type === 'editor'">
            <editor
              :editorContent="addForm[item.field]"
              :editorConfig="editorConfig"
              @setEditorValue="setEditorValue"
              @linkCheck="linkCheck"
              @pasteTextHandle="pasteTextHandle"
              @linkImgCheck="linkImgCheck"
              @linkImgCallback="linkImgCallback"
              @customInsertUploadImgHooks="customInsertUploadImgHooks"
              @beforeUploadImgHooks="beforeUploadImgHooks"
              @successUploadImgHooks="successUploadImgHooks"
              @failUploadImgHooks="failUploadImgHooks"
              @errorUploadImgHooks="errorUploadImgHooks"
              @timeoutUploadImgHooks="timeoutUploadImgHooks"
            />
          </div>
        </template>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
export default {
  name: "FormView",
  props: {
    items: {
      type: Array,
      default: function () {
        return [];
      },
    }, // 表单中的每一项
    rules: {
      type: Object,
      default: function () {
        return {};
      },
    },
    labelWidth: {
      type: String,
      default: "auto",
    }, // label的宽
    position: {
      type: String,
      default: "right",
    }, // 通过设置 label-position 属性可以改变表单标签的位置，可选值为 top、left、right，当设为 top 时标签会置于表单域的顶部，left、right是对齐方向
    formSize: {
      type: String,
      default: "small",
    }, // 用于控制该表单内组件的尺寸 medium 正常/ small 小/ mini 迷你
    valueWidth: {
      type: String,
      default: "200px",
    }, // input输入框的宽
    addForm: {
      type: Object,
      default: function () {
        return {};
      },
    }, // 表单数据对象
    isInline: {
      type: Boolean,
      default: false,
    }, // 让表单域变为行内的表单域
    collapseTags: {
      type: Boolean,
      default: false,
    }, // 多选下拉框 多选时是否将选中值按文字的形式展示
    filterable: {
      type: Boolean,
      default: false,
    }, // 下拉框、多选下拉框、级联框可搜索
    showAlpha: {
      type: Boolean,
      default: false,
    }, // 是否支持透明度选择
    predefineColors: {
      type: Array,
      default: function () {
        return [];
      },
    }, // 预定义颜色
    uploadConfig: {
      type: Object,
      default: function () {
        return {};
      },
    }, // 文件上传配置
    editorConfig: {
      type: Object,
      default: function () {
        return {};
      },
    }, // 富文本编辑器配置
  },
  data() {
    return {
      uploadAttr: {
        action: "#", // 必选参数，上传的地址
        headers: {}, // 设置上传的请求头部
        multiple: true, // 是否支持多选文件
        data: {}, // 上传时附带的额外参数
        name: "", // 上传的文件字段名
        withCredentials: false, // 支持发送 cookie 凭证信息
        showFileList: true, // 是否显示已上传文件列表
        drag: false, // 是否启用拖拽上传
        accept: "", // 接受上传的文件类型
        listType: "text", // 文件列表的类型
        autoUpload: false, // 是否在选取文件后立即进行上传
        disabled: false, // 是否禁用
        limit: 10, // 最大允许上传个数
        btnTitle: "点击上传", // 按钮文字
        slotContent: "", // 提示说明文字
      },
      dialogVisible: false,
      dialogImageUrl: "",
    };
  },
  watch: {
    uploadConfig: {
      handler: function (val) {
        this.uploadAttr = Object.assign(this.uploadAttr, val);
      },
      immediate: true,
      deep: true,
    },
  },
  created() {
    this.$set(this.uploadConfig);
  },
  mounted() {},
  computed: {
    showList() {
      return this.items ? this.items.filter(el => !el.hidden) : [];
    }
  },
  methods: {
    // 带输入建议的输入框 输入建议的方法属性
    autocompleteQuerySearch(queryString, cb, item) {
      this.$emit("on-autocomplete-query-search", queryString, cb, item);
    },
    // 选择的回调函数
    autocompleteHandleSelect(value, item) {
      this.$emit("on-autocomplete-select", { value, item });
    },
    // 数字
    changeNumber(number) {
      this.$emit("on-change-number", number);
    },
    // 日期
    changeDate(date) {
      this.$emit("on-change-date", date);
    },
    // 年
    changeYear(year) {
      this.$emit("on-change-year", year);
    },
    // 月
    changeMonth(month) {
      this.$emit("on-change-month", month);
    },
    // 时间日期
    changeDateTimeRange(dataTimeRange) {
      this.$emit("on-change-date-time-range", dataTimeRange);
    },
    // 日期
    changeDateRange(dataRange) {
      this.$emit("on-change-date-range", dataRange);
    },
    // 下拉框
    changeOption(value, item) {
      let me = this;
      let label = "";
      item.option.forEach((d) => {
        d.value === value && (label = d.label);
      });
      this.items.forEach((d) => {
        if (d.label === item.label) {
          me.$set(d, "value", value);
        }
      });
      this.$emit("on-change-option", {
        item: item,
        label: label,
        value: value,
      });
    },
    // 可编辑的下拉菜单
    editSelectChange(item) {
      this.$emit("on-edit-select-change", item);
    },
    // 多选下拉框
    changeMultOption(value, item) {
      this.$emit("on-change-multi-option", { value, item });
    },
    // 级联下拉框
    cascaderSelectChange(item) {
      this.$emit("on-cascader-select-change", item);
    },
    // 级联下拉框
    cascaderItemChange(label, item) {
      this.$emit("on-cascader-item-change", {
        label: label,
        nodes: item ? item.options : null,
      });
    },
    // 单选框
    changeRadio(label) {
      this.$emit("on-change-radio", label);
    },
    // 多选框
    checkedChange(value) {
      this.$emit("on-checked-change", value);
    },
    // 当绑定值变化时触发
    colorPickerChange(value) {
      this.$emit("on-change-color-picker", value);
    },
    // 面板中当前显示的颜色发生改变时触发
    colorPickerActiveChange(value) {
      this.$emit("on-active-change-color-picker", value);
    },
    // 清除表单内容
    resetFields() {
      this.$refs.addFormRef.resetFields();
    },
    // 验证规则是否满足
    validate() {
      let that = this,
        promise = null;
      promise = new Promise((resolve, reject) => {
        that.$refs.addFormRef.validate((valid) => {
          valid ? resolve(valid) : reject(valid);
        });
      });
      return promise;
    },
    // 手动上传文件
    submit() {
      if (this.$refs.upload) {
        if (this.$refs.upload instanceof Array) {
          this.$refs.upload[0].submit();
        } else {
          this.$refs.upload.submit();
        }
      }
    },
    // 点击文件列表中已上传的文件时的钩子
    onPreview(file) {
      if (file.url) {
        this.dialogImageUrl = file.url;
        this.dialogVisible = true;
      }
      this.$emit("on-preview", file);
    },
    // 文件列表移除文件时的钩子
    onRemove(file, fileList) {
      this.$emit("on-remove", {
        file,
        fileList,
      });
    },
    // 文件上传成功时的钩子
    onSuccess(response, file, fileList) {
      this.$emit("on-success", {
        response,
        file,
        fileList,
      });
    },
    // 文件上传失败时的钩子
    onError(err, file, fileList) {
      this.$emit("on-error", {
        err,
        file,
        fileList,
      });
    },
    // 文件上传时的钩子
    onProgress(event, file, fileList) {
      this.$emit("on-progress", {
        event,
        file,
        fileList,
      });
    },
    // 文件状态改变时的钩子，添加文件、上传成功和上传失败时都会被调用
    onChange(file, fileList) {
      this.$emit("on-change", {
        file,
        fileList,
      });
    },
    // 上传文件之前的钩子，参数为上传的文件，若返回 false 或者返回 Promise 且被 reject，则停止上传。
    beforeUpload(file) {
      this.$emit("before-upload", file);
    },
    // 删除文件之前的钩子，参数为上传的文件和文件列表，若返回 false 或者返回 Promise 且被 reject，则停止删除。
    beforeRemove(file, fileList) {
      this.$emit("before-remove", {
        file,
        fileList,
      });
    },
    // 富文本编辑器修改内容
    setEditorValue(html) {
      this.items.forEach((el) => {
        if (el.type === "editor") {
          this.addForm[el.field] = html;
        }
      });
      this.$emit("setEditorValue", html);
    },
    // 插入链接时候的格式校验 args中text是插入的文字 link是插入的链接
    linkCheck({ text, link }) {
      this.$emit("linkCheck", { text, link });
    },
    // 对粘贴的文字进行自定义处理，返回处理后的结果。编辑器会将处理后的结果粘贴到编辑区域中。IE 暂时不支持  content 即粘贴过来的内容（html 或 纯文本），可进行自定义处理然后返回
    pasteTextHandle(content) {
      this.$emit("pasteTextHandle", content);
    },
    // 插入网络图片的校验 src即图片的地址
    linkImgCheck(src) {
      this.$emit("linkImgCheck", src);
    },
    // 插入网络图片的回调  url 即插入图片的地址
    linkImgCallback(url) {
      this.$emit("linkImgCallback", url);
    },
    // 图片上传(上传到服务器)并返回结果，自定义插入图片的事件，而不是编辑器自动插入图片
    customInsertUploadImgHooks({ insertLinkImg, result, editor }) {
      this.$emit("customInsertUploadImgHooks", {
        insertLinkImg,
        result,
        editor,
      });
    },
    // 图片上传(上传到服务器)之前触发
    beforeUploadImgHooks({ xhr, editor, files }) {
      this.$emit("beforeUploadImgHooks", { xhr, editor, files });
    },
    // 图片上传(上传到服务器)并返回结果，图片插入成功之后触发
    successUploadImgHooks({ xhr, editor, result }) {
      this.$emit("successUploadImgHooks", { xhr, editor, result });
    },
    // 图片上传(上传到服务器)并返回结果，图片插入错误时触发
    failUploadImgHooks({ xhr, editor, result }) {
      this.$emit("failUploadImgHooks", { xhr, editor, result });
    },
    // 图片上传(上传到服务器)出错时触发
    errorUploadImgHooks({ xhr, editor }) {
      this.$emit("errorUploadImgHooks", { xhr, editor });
    },
    // 图片上传(上传到服务器)超时时触发
    timeoutUploadImgHooks({ xhr, editor }) {
      this.$emit("timeoutUploadImgHooks", { xhr, editor });
    },
  },
};
</script>

<style rel="stylesheet/scss" lang="scss" scoped>
@import "../../../assets/styles/base_style";

.s-form-view-container {
  width: 100%;
}
</style>
